/*
* Copyright (c) 2007 by Kirill Kolodyazhniy.
* See the file "license.terms" for information on usage and redistribution.
*/

#include "solid.h"

namespace Engine
{
	/***************************************************************************************************************/
	Solid::Solid(const std::string& name, SceneNodePtr node)
		:m_name(name)
		,m_node(node)		
	{
		node->UpdateSignal.Connect<ImmediateExecute>(this,&Solid::UpdateTransform);
	}
	/***************************************************************************************************************/
	Solid::~Solid()
	{
		m_forces.clear();
	}	
	/***************************************************************************************************************/
	void Solid::SetTransform(const Matrix4<REAL>& t)
	{
		SetTransformImpl(t);
		m_node->SetTransform(t);
	}
	/***************************************************************************************************************/
	const Matrix4<REAL>& Solid::GetTransform() const
	{		
		return m_node->GetTransform();
	}
	/***************************************************************************************************************/
	void Solid::AddShape(const ShapeData& shape)
	{
		EntityPtr entity = shape.entity;
		if(!entity.IsNull())
		{
			if(shape.position == Matrix4<REAL>::IDENTITY)
			{
				m_node->AttachObject(entity);
			}
			else
			{			
				SceneNodePtr child = m_node->CreateChild(entity->GetName());
				child->SetTransform(shape.position);
				m_node->AttachObject(entity);
			}
		}
		AddShapeImpl(shape);
	}
	/***************************************************************************************************************/
	void Solid::AddForce(const Force& f)
	{
		m_forces.push_back(f);
	}
	/***************************************************************************************************************/
	void Solid::ZeroForces()
	{
		ZeroForcesImpl();
		m_forces.clear();
	}
	/***************************************************************************************************************/	
	void Solid::UpdateTransform()
	{
		m_node->SetTransform(GetTransformImpl());
	}
	/***************************************************************************************************************/	
	void Solid::ApplyForces(REAL step)
	{
		if (IsStatic())
			return ;

		REAL invStep = 1 / step;

		ForceVector::iterator i = m_forces.begin(), e = m_forces.end();
		for (;i != e;)
		{
			if (true == i->singleStep)
			{
				i->duration = step;
			}
			else if (i->duration < step)
			{
				// Scale the size of the force/torque.
				i->vec *= (i->duration * invStep);
			}

			// Apply the actual force/torque.
			ApplyForce(*i);

			// The following is ok for all cases (even when duration is < mStepSize).
			i->duration -= step;

			if (i->duration <= 0)
			{
				// Delete this force.
				*i = m_forces.back();
				m_forces.pop_back();
			}
			else
			{
				++i;
			}
		}
	}
	/***************************************************************************************************************/	
}
